﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Xml;
using System.IO;
using ICSharpCode.SharpZipLib.Zip;
using System.Diagnostics;
using ICSharpCode.SharpZipLib.Core;

namespace BIM3DXMLExport
{
    class XMLGenerator
    {
        public bool Create3DXMLFile(string fileName)
        {
            string AddInPath = BIM3DXMLExportUI.AddInPath;
            string directoryName = Path.GetDirectoryName(AddInPath);
            string foldPath = directoryName + @"\3DXML";
            if (!Directory.Exists(foldPath))
            {
                Directory.CreateDirectory(foldPath);
            }
            //Step1: Manifest file
            GenerateManifestFile(foldPath + @"\Manifest.xml");
            //Setp2: Model structure file WH.3dxml//TODO
            GenerateWH3DXMLFile(foldPath + @"\WH.3dxml");
            //Step3: 3DRep file for geometry WH_**.3DRep//TODO
            Generate3DRepFile(foldPath + @"\WH_1.3DRep");
            //Step4: Create zip (3dxml) file
            bool suc = CreateZipFile(foldPath, fileName);
            //Step5: Delete all the file on "foldPath"
            DirectoryInfo di = new DirectoryInfo(foldPath);
            di.Delete(true);
            return suc;
        }

        private bool CreateZipFile(string filesPath, string zipFilePath)
        {
            bool suc = false;
            if (!Directory.Exists(filesPath))
            {
                Console.WriteLine("Cannot find directory '{0}'", filesPath);
                return suc;
            }

            try
            {
                string[] filenames = Directory.GetFiles(filesPath);
                using (ZipOutputStream s = new ZipOutputStream(File.Create(zipFilePath)))
                {

                    s.SetLevel(9); // 压缩级别 0-9
                    //s.Password = "123"; //Zip压缩文件密码
                    byte[] buffer = new byte[4096]; //缓冲区大小
                    foreach (string file in filenames)
                    {
                        ZipEntry entry = new ZipEntry(Path.GetFileName(file));
                        entry.DateTime = DateTime.Now;
                        s.PutNextEntry(entry);
                        using (FileStream fs = File.OpenRead(file))
                        {
                            int sourceBytes;
                            do
                            {
                                sourceBytes = fs.Read(buffer, 0, buffer.Length);
                                s.Write(buffer, 0, sourceBytes);
                            } while (sourceBytes > 0);
                        }
                    }
                    s.Finish();
                    s.Close();
                }
                suc = true;
            }
            catch (Exception ex)
            {
                Console.WriteLine("Exception during processing {0}", ex);
                suc = false;
            }
            return suc;
        }

        public void Generate3DRepFile(string strPath)
        {
            try
            {
                XmlDocument doc = new XmlDocument();
                doc.AppendChild(doc.CreateXmlDeclaration("1.0", "utf-8", null));
                XmlElement XMLRepresentation = doc.CreateElement("XMLRepresentation");
                doc.AppendChild(XMLRepresentation);
                XmlAttribute version = doc.CreateAttribute("version");
                version.Value = "1.2";
                XmlAttribute xlns = doc.CreateAttribute("xmlns");
                xlns.Value = "http://www.3ds.com/xsd/3DXML";
                XmlAttribute xsi = doc.CreateAttribute("xmlns:xsi");
                xsi.Value = "http://www.w3.org/2001/XMLSchema-instance";
                XMLRepresentation.Attributes.Append(version);
                XMLRepresentation.Attributes.Append(xlns);
                XMLRepresentation.Attributes.Append(xsi);

                XmlElement Root = doc.CreateElement("Root");
                XMLRepresentation.AppendChild(Root);
                XmlAttribute Rootxsitype = doc.CreateAttribute("xsi:type", "http://www.w3.org/2001/XMLSchema-instance");
                Rootxsitype.Value = "BagRepType";
                Root.Attributes.Append(Rootxsitype);

                XmlElement Rep = doc.CreateElement("Rep");
                Root.AppendChild(Rep);
                XmlAttribute Repxsitype = doc.CreateAttribute("xsi:type", "http://www.w3.org/2001/XMLSchema-instance");
                Repxsitype.Value = "PolygonalRepType";
                XmlAttribute RepId = doc.CreateAttribute("id");
                RepId.Value = "1";
                XmlAttribute Repaccuracy = doc.CreateAttribute("accuracy");
                Repaccuracy.Value = "0";
                XmlAttribute Repsolid = doc.CreateAttribute("solid");
                Repsolid.Value = "1";
                Rep.Attributes.Append(Repxsitype);
                Rep.Attributes.Append(RepId);
                Rep.Attributes.Append(Repaccuracy);
                Rep.Attributes.Append(Repsolid);

                XmlElement Faces = doc.CreateElement("Faces");
                Rep.AppendChild(Faces);
                XmlElement Face = doc.CreateElement("Face");
                XmlAttribute triangles = doc.CreateAttribute("triangles");
                triangles.Value = "1 2 3 0";
                Face.Attributes.Append(triangles);
                Faces.AppendChild(Face);
                XmlElement SurfaceAttributes = doc.CreateElement("SurfaceAttributes");
                Face.AppendChild(SurfaceAttributes);
                XmlElement Color = doc.CreateElement("Color");
                SurfaceAttributes.AppendChild(Color);
                XmlAttribute Colorxsitype = doc.CreateAttribute("xsi:type", "http://www.w3.org/2001/XMLSchema-instance");
                Colorxsitype.Value = "RGBAColorType";
                XmlAttribute Red = doc.CreateAttribute("red");
                Red.Value = "0.752941";
                XmlAttribute green = doc.CreateAttribute("green");
                green.Value = "0.752941";
                XmlAttribute blue = doc.CreateAttribute("blue");
                blue.Value = "0.752941";
                XmlAttribute alpha = doc.CreateAttribute("alpha");
                alpha.Value = "1.00";
                Color.Attributes.Append(Colorxsitype);
                Color.Attributes.Append(Red);
                Color.Attributes.Append(green);
                Color.Attributes.Append(blue);
                Color.Attributes.Append(alpha);


                XmlElement VertexBuffer = doc.CreateElement("VertexBuffer");
                Rep.AppendChild(VertexBuffer);
                XmlElement Positions = doc.CreateElement("Positions");
                Positions.InnerText = "4.0 0.0 0.0";
                VertexBuffer.AppendChild(Positions);
                XmlElement Normals = doc.CreateElement("Normals");
                Normals.InnerText = "4.0 0.0 0.0";
                VertexBuffer.AppendChild(Normals);

                doc.Save(strPath);
            }
            catch (System.Exception ex)
            {
                String error = ex.ToString();
                Console.WriteLine(error);
            }
        }

        public void GenerateWH3DXMLFile(string strPath)
        {
            try
            {
                XmlDocument doc = new XmlDocument();
                doc.AppendChild(doc.CreateXmlDeclaration("1.0", "utf-8", null));
                XmlElement Model = doc.CreateElement("Model_3dxml");
                doc.AppendChild(Model);
                XmlAttribute xlns = doc.CreateAttribute("xmlns");
                xlns.Value = "http://www.pengrui.com/3DXML";
                XmlAttribute xsi = doc.CreateAttribute("xmlns:xsi");
                xsi.Value = "http://www.w3.org/2001/XMLSchema-instance";
                XmlAttribute xsispace = doc.CreateAttribute("xmlns:xlink");
                xsispace.Value = "http://www.w3.org/1999/xlink";
                Model.Attributes.Append(xlns);
                Model.Attributes.Append(xsi);
                Model.Attributes.Append(xsispace);

                XmlElement Header = doc.CreateElement("Header");
                Model.AppendChild(Header);
                XmlElement SchemaVersion = doc.CreateElement("SchemaVersion");
                SchemaVersion.InnerText = "4.0";
                Header.AppendChild(SchemaVersion);

                XmlElement ProductStructure = doc.CreateElement("ProductStructure");
                XmlAttribute Psroot = doc.CreateAttribute("root");
                Psroot.Value = "1";
                ProductStructure.Attributes.Append(Psroot);
                Model.AppendChild(ProductStructure);

                XmlElement Reference3D = doc.CreateElement("Reference3D");
                ProductStructure.AppendChild(Reference3D);
                XmlAttribute Reference3Dxsitype = doc.CreateAttribute("xsi", "type", "http://www.w3.org/2001/XMLSchema-instance");
                Reference3Dxsitype.Value = "Reference3DType";
                XmlAttribute Reference3DID = doc.CreateAttribute("id");
                Reference3DID.Value = "1";
                XmlAttribute Reference3DName = doc.CreateAttribute("name");
                Reference3DName.Value = "Revit模型";
                Reference3D.Attributes.Append(Reference3Dxsitype);
                Reference3D.Attributes.Append(Reference3DID);
                Reference3D.Attributes.Append(Reference3DName);



                XmlElement DefaultView = doc.CreateElement("DefaultView");
                Model.AppendChild(DefaultView);
                XmlElement Viewpoint = doc.CreateElement("Viewpoint");
                DefaultView.AppendChild(Viewpoint);
                XmlAttribute xsitype = doc.CreateAttribute("xsi:type", "http://www.w3.org/2001/XMLSchema-instance");
                xsitype.Value = "ParallelViewpointType";
                XmlAttribute visualizedHeight = doc.CreateAttribute("visualizedHeight");
                visualizedHeight.Value = "12908.85871";
                XmlAttribute targetDistance = doc.CreateAttribute("targetDistance");
                targetDistance.Value = "53769.26563";
                XmlAttribute nearPlaneDistance = doc.CreateAttribute("nearPlaneDistance");
                nearPlaneDistance.Value = "28129.89063";
                XmlAttribute farPlaneDistance = doc.CreateAttribute("farPlaneDistance");
                farPlaneDistance.Value = "79408.67969";
                Viewpoint.Attributes.Append(xsitype);
                Viewpoint.Attributes.Append(visualizedHeight);
                Viewpoint.Attributes.Append(targetDistance);
                Viewpoint.Attributes.Append(nearPlaneDistance);
                Viewpoint.Attributes.Append(farPlaneDistance);

                XmlElement Position = doc.CreateElement("Position");
                Position.InnerText = "4.0";
                XmlElement Sight = doc.CreateElement("Sight");
                Sight.InnerText = "4.0";
                XmlElement Right = doc.CreateElement("Right");
                Right.InnerText = "4.0";
                XmlElement Up = doc.CreateElement("Up");
                Up.InnerText = "4.0";
                Viewpoint.AppendChild(Position);
                Viewpoint.AppendChild(Sight);
                Viewpoint.AppendChild(Right);
                Viewpoint.AppendChild(Up);

                doc.Save(strPath);
            }
            catch (System.Exception ex)
            {
                String error = ex.ToString();
                Console.WriteLine(error);
            }
        }

        public void GenerateManifestFile(string strPath)
        {
            try
            {
                //定义一个XDocument结构
                XmlDocument doc = new XmlDocument();
                doc.AppendChild(doc.CreateXmlDeclaration("1.0", "utf-8", null));
                XmlElement Manifest = doc.CreateElement("Manifest");
                doc.AppendChild(Manifest);
                XmlAttribute xsi = doc.CreateAttribute("xmlns:xsi");
                xsi.Value = "http://www.w3.org/2001/XMLSchema-instance";
                XmlAttribute xsispace = doc.CreateAttribute("xsi:noNamespaceSchemaLocation", "http://www.w3.org/2001/XMLSchema-instance");
                xsispace.Value = "Manifest.xsd";
                Manifest.Attributes.Append(xsi);
                Manifest.Attributes.Append(xsispace);

                XmlElement Root = doc.CreateElement("Root");
                Root.InnerText = "WH.3dxml";
                XmlElement WithAuthoringData = doc.CreateElement("WithAuthoringData");
                WithAuthoringData.InnerText = "false";
                Manifest.AppendChild(Root);
                Manifest.AppendChild(WithAuthoringData);


                //XDocument myDoc = new XDocument(
                //    new XElement("Manifest",
                //        new XElement("Root", "RP.3dxml"),
                //        new XElement("WithAuthoringData", "false")
                //        ));
                doc.Save(strPath);
            }
            catch (System.Exception ex)
            {
                String error = ex.ToString();
                Console.WriteLine(error);
            }
        }
    }
}
